#include "rules.h"
#define ACHAR "#"
mquery::mquery()
{
    try
    {
       c.connect(HOSTNAME);
       fetchRules();
    }
    catch(mongo::DBException e)
    {
        cerr<<"Error connecting DB:"<<e.what()<<endl;
    }
}
void mquery::fetchRules()
{
    try
    {
        mongo::BSONObj q=mongo::fromjson("{}");
        cursor=c.query(RULE,q);
        while(cursor->more())
        {
            mongo::BSONObj x=cursor->nextSafe().getOwned();
            rules.push_back(x);
        }
    }
    catch(mongo::DBException e)
    {
        cerr<<e.what()<<endl;
    }
}
void mquery::printRules()
{
    std::list<mongo::BSONObj>::iterator i;
    for(i=rules.begin();i!=rules.end();i++)
    {
        cout<<i->toString()<<endl;
    }
}
bool mquery::doQuery(std::string coll,mongo::BSONObj b)
{
    try
    {
        cursor=c.query(coll,b);
    }
    catch(mongo::DBException e)
    {
        cerr<<"Error querying DB:"<<e.what()<<endl;
        return false;
    }
    return true;
}
mongo::BSONObj mquery::filler(mongo::BSONObj &rule,mongo::BSONObj &obj)
{
    if(rule.isEmpty()||obj.isEmpty())
    {
        return mongo::BSONObj();
    }
    mongo::BSONObjBuilder x;
    int isFieldMissing=0;
    std::set<string> fnames;
    rule.getFieldNames(fnames);
    std::set<string>::iterator i;
    //std::cout<<"In filler:"<<std::endl;
	mongo::BSONObj ruleEmbeddedObj,objEmbeddedObj;
    for(i=fnames.begin();i!=fnames.end();i++)
    {
        std::string fieldName=*i;
        //std::cout<<fieldName<<std::endl;
	    if(obj.hasField(fieldName.c_str()))
        {
            switch(rule[fieldName].type())
            {
                case mongo::String:
                    if (rule[fieldName].str()==ACHAR)
                    {
                        x.append(obj[fieldName]);
                    }
                    else
                    {
                        x.append(rule[fieldName]);
                    }
                    break;
                case mongo::Object:
                    ruleEmbeddedObj=rule[fieldName].Obj();
                    objEmbeddedObj=obj[fieldName].Obj();
                    x.append(fieldName,filler(ruleEmbeddedObj,objEmbeddedObj));
		            break;
                default:
                    x.append(rule[fieldName]);
            }
        }
	    else
        {
            return mongo::BSONObj();
        }
    }
    return x.obj();
}
std::list<std::string> mquery::match(mongo::BSONObj &obj)
{
    std::list<mongo::BSONObj>::iterator i;
    std::list<string> matched;
   
    for(i=rules.begin();i!=rules.end();i++)
    {
        bool ismatch=false;
        //std::cout<<obj.toString()<<std::endl;
        mongo::BSONObj &b=*i;
        //std::cout<<"alert:"<<b["alert"].str()<<std::endl;
        //std::cout<<"continue:"<<b["continue"].str()<<std::endl;
        mongo::BSONObj logic=b["logic"].Obj();
        std::string lib=logic["lib"].str();
        //std::cout<<"library:"<<lib<<std::endl;
	    if(lib=="isValidCVE")
        {
            if(obj.hasField("DIP") && obj.hasField("CVE"))
            ismatch=isValidCVE(&c,obj["DIP"].str(),obj["CVE"].str());
        }
        else if(lib=="hasCount")
        {
            mongo::BSONObj qy=logic["query"].Obj();
            mongo::BSONObj a=filler(qy,obj);
            //std::cout<<a.toString()<<std::endl;
            if(!a.isEmpty())
            ismatch=hasCount(&c,logic["operator"].str(),logic["value"].numberInt(),a);
        }
        else if(lib=="")
        {
            Comp co;
            std::string fname=logic["query"].str();
            switch(obj[fname].type())
            {
                case mongo::String:
                ismatch=co.compare(obj[fname].str(),logic["operator"].str(),logic["value"].str());
                break;
                case mongo::NumberInt:
                ismatch=co.compare(obj[fname].numberInt(),logic["operator"].str(),logic["value"].numberInt());
                break;
                case mongo::NumberDouble:
                ismatch=co.compare(obj[fname].numberDouble(),logic["operator"].str(),logic["value"].numberDouble());
                break;
            }
        }
        if(ismatch==true)
        {
            mongo::BSONElement oid;
            i->getObjectID(oid);
            matched.push_back(oid.__oid().toString());
        }
        //std::cout<<"--------------------------------------------------------"<<std::endl;

     }
     return matched;
}

